#include <myFs/simpleFS.h>
#include <spdlog/spdlog.h>

namespace myFs {
namespace basic {
using namespace spdlog;

SimpleFS::~SimpleFS() = default;
SimpleFS::SimpleFS(::std::string path) : m_helper(path) { info("Simple FS construct"); }

int SimpleFS::getattr(std::string const& path, Inode& stat) {
    debug("func={} path={}", __func__, path);
    return m_helper.getattrHelper(m_helper.toInum(path), stat);
}

int SimpleFS::readdir(std::string const& path, std::vector<DirEntry>& dir) {
    debug("func={} path={}", __func__, path);
    return m_helper.readdirHelper(m_helper.toInum(path), dir);
}
int SimpleFS::write(std::string const& path, char const* buf, size_t size, size_t off) {
    debug("func={} args={}, size={},off={}", __func__, path, size, off);
    return m_helper.writeHelper(m_helper.toInum(path), buf, size, off);
}
int SimpleFS::read(std::string const& path, char* buf, size_t size, size_t off) {
    debug("func={} args={}, size={},off={}", __func__, path, size, off);
    return m_helper.readHelper(m_helper.toInum(path), buf, size, off);
}
int SimpleFS::rename(std::string const& path1, std::string const& path2) {
    debug("func={} args={}, {}", __func__, path1, path2);
    std::string fpath1, name1, fpath2, name2;
    getFatherDirAndName(path1, fpath1, name1);
    getFatherDirAndName(path2, fpath2, name2);
    debug("func={} fpath1={} fpath2", __func__, fpath1, fpath2);
    debug("func={} oldname={}, newname={}", __func__, name1, name2);
    size_t pinum1 = m_helper.toInum(fpath1);
    if (pinum1 == -1) return -ENOENT;
    size_t inum1 = dirLookup(pinum1, name1);
    if (inum1 == -1) return -ENOENT;
    size_t pinum2 = m_helper.toInum(fpath2);
    if (pinum2 == -1) return -ENOENT;
    return m_helper.renameHelper(pinum1, inum1, pinum2, name2);
}
int SimpleFS::rmdir(std::string const& path) {
    debug("func={} args={}", __func__, path);
    return m_helper.releasedirHelper(m_helper.toInum(path));
}
int SimpleFS::mkdir(std::string const& path) {
    debug("func={} args={}", __func__, path);
    std::string fatherpath, filename;
    getFatherDirAndName(path, fatherpath, filename);
    size_t inum = m_helper.toInum(fatherpath);
    if (inum == -1) return -ENOENT;
    return m_helper.mkdirHelper(inum, filename);
}
int SimpleFS::mknod(std::string const& path) {
    debug("func={} args={}", __func__, path);
    std::string fatherpath, filename;
    getFatherDirAndName(path, fatherpath, filename);
    size_t inum = m_helper.toInum(fatherpath);
    if (inum == -1) return -ENOENT;
    return m_helper.mknodHelper(inum, filename);
}

int SimpleFS::unlink(std::string const& path) {
    std::string fatherpath, filename;
    getFatherDirAndName(path, fatherpath, filename);
    debug("func={}, fatherpath={}, filename={}", __func__, fatherpath, filename);
    size_t finum = m_helper.toInum(fatherpath);
    return m_helper.unlinkHelper(finum, dirLookup(finum, filename));
}
int SimpleFS::releasedir(std::string const& path) {
    std::string fatherpath, filename;
    getFatherDirAndName(path, fatherpath, filename);
    size_t finum = m_helper.toInum(fatherpath);
    size_t cinum = dirLookup(finum, filename);
    m_helper.removeDirEntry(finum, cinum);
    return m_helper.releasedirHelper(cinum);
}

void SimpleFS::getFatherDirAndName(std::string const& path, std::string& fatherpath, std::string& filename) {
    auto pos   = path.find_last_of('/');
    fatherpath = path.substr(0, pos);
    filename   = path.substr(pos + 1);
}

size_t SimpleFS::dirLookup(size_t inum, std::string const& filename) {
    if (inum == -1) return -1;
    std::vector<DirEntry> dir;
    debug("func={} try to lookup {} in  inum={}", __func__, filename, inum);
    m_helper.readdirHelper(inum, dir);
    for (auto& [name, ret_inum] : dir) {
        // debug("func={} dirname={}, dirinum={}", __func__, name,
        // ret_inum);
        if (std::string(name) == filename) { return ret_inum; }
    }
    debug("func={} msg={}", __func__, "no found");
    // debug("func={} ret={}", __func__, -1);
    return -1;
}

int SimpleFS::open(std::string const& path) {
    debug("func={} path={}", __func__, path);
    return m_helper.openHelper(m_helper.toInum(path));
}

}  // namespace basic
}  // namespace myFs